package com.yq.interview.study.thread;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName MyThreadPoolDemo
 * @Description 线程池，
 * 继承thread/runable/callable/线程池
 * 需要对象依赖注入，
 * 第四种线程池
 *
 * 线程池工作原理，线程池几个重要参数，分析线程池怎么做，阻塞队列的作用是什么，使用无界阻塞队列会出现什么情况
 * @Author yaoqiang
 * @Date 2020/11/23 16:31
 * @Version 1.0
 */
public class MyThreadPoolDemo {
    public static void main(String[] args) {
        //  threadPool();

        System.out.println(Runtime.getRuntime().availableProcessors());
        //第一知道我们运行的核数是几核，Runtime.getRuntime().availableProcessors()
        // CPU密集型：如果是核数8核，则cpu核数+1，
        // IO密集型：
        // 方式一cpu一直执行任务：CPU核数/(1-0.9)得到线程数 比如8/（1-0.9）=80线程；阻塞系数是0.8-0.9
        // ；方式2，如果CPU不是一直执行任务：核数8核，则8*2=16，配置最大16，
        //线程池7大参数
        ExecutorService threadPool = new ThreadPoolExecutor(2, 5,
                1L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
        try {
            for (int i = 1; i <= 9; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName());
                });
            }
            //  threadPool.submit();
        } catch (Exception e) {
            threadPool.shutdown();
        }
    }


    private static void threadPool2() {
        //查看核数
        System.out.println(Runtime.getRuntime().availableProcessors());
//array有工具类arrays,collection collections executor executors
        List<String> list = Arrays.asList("1", "2");
        // Executors.newScheduledThreadPool();//时间调度的
        ExecutorService threadPool = Executors.newFixedThreadPool(5);//一池五线程
        ExecutorService threadPool2 = Executors.newCachedThreadPool();//一池N线程
        ExecutorService threadPool3 = Executors.newSingleThreadExecutor();//一池N线程
        //jdk中这三个一个都不用，都是自己写的阻塞队列，阿里巴巴开发手册说




/*        public static ExecutorService newFixedThreadPool(int nThreads) {
            return new ThreadPoolExecutor(nThreads, nThreads,
                    0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<Runnable>());
            public static ExecutorService newCachedThreadPool() {
                return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                        60L, TimeUnit.SECONDS,
                        new SynchronousQueue<Runnable>());
                public static ExecutorService newSingleThreadExecutor() {
                    return new Executors.FinalizableDelegatedExecutorService
                            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));*/

        //模拟十个用户来提交，只有五个池子
        try {
            for (int i = 1; i <= 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName());
                });
            }
            //  threadPool.submit();
        } catch (Exception e) {
            threadPool.shutdown();
        }
    }
}

/***
 *
 * ****************************************
 线程池底层工作原理
 1、在创建线程池后，等待提交过来的任务请求。
 2、当调用execute()方法添加一个请求任务，线程池会做如下判断：
    2.1如果真在运行线程数小于corePoolSize，直接创建线程运行。
    2.2如果正在运行的线程数大于等于corePoolSize,将这个任务放在队列workQueue
    2.3如果队列满了，核心线程数还小于最大线程数，创建非核心线程来运行这个任务。
    2.4如果队列满了，运行的线程数大于等于最大线程数，则启动饱和拒绝策略来执行
 3.当一个线程完成任务，它会从队列中取下一个任务来执行
 4.当一个线程无事可做超过一定的时间keepAliveTime,线程池会判断；
    如果当前运行线程数大于corePoolSize，这个线程就会被停掉，线程池中所有任务完成后最终会收缩到corePoolSize的大小
************************************
 jdk中这三个一个都不用，都是自己写的阻塞队列，阿里巴巴开发手册说
 线程资源必须通过线程池来提供，不允许应用中自行显式创建线程：线程池的好处是减少创建和销毁线程的时间，以及资源的开销，解决资源不足的问题，
 如果不适用，可能会造成系统创建大量线程而导致消耗完内存或者过度切换的问题

 为什么：
 线程池不允许使用executors去创建，二十通过ThreadPoolExecutor的方式。可以避免消耗资源的风险
 executors返回线程对象的弊端
 newFixedThreadPool和singleThreadPool允许请求的队列长度为Integer.MAX_VALUE,可能会堆积大量请求，导致OOM
 CacheThreadPool和ScheduledThreadPool允许创建的线程数是INTEGER.MAX_VALUE,可能会创建大量的线程，导致OOM


 *
 *
 *
 */